package com.googlecode.gwtptk.client;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HTMLTable;
import com.google.gwt.user.client.ui.Widget;

import java.util.ArrayList;

/**
 * DataTable creates data table that will have columns according to the list of the names used in header.
 * It is meant to be subclassed in order to customize its columns.
 * <p/>
 * Example of creation:
 * <pre>
	private class UserDataTable extends DataTable {
		private UserDataTable() {
			defineColumns(new DataColumn("Name"),
				new DataColumn("Age").setStyle("right"),
				new DataColumn("Address"),
				new DataColumn("E-mail"),
				new DataColumn("Note"),
                new DataColumn().setMinWidth()); // this one for function buttons
		}
	}</pre>
 * <p/>
 * Example of usage:
 * <pre>
	for (final User user : ...userlist...) {
        Panel functionButtons = ...; // here create panel with buttons - can be customized per user
		table.addRow(user.getName(),
			user.getAge(),
			user.getAddress(),
			user.getEmail(),
			user.getNote(),
            functionButtons);
	}</pre>
 *
 * @author Richard Richter
 */
public abstract class DataTable extends FlexTable {
	private int row;
	private ArrayList<Integer> ignoreClicksOnColumns = new ArrayList<Integer>();

	/**
	 * Creates empty table - use {@link #makeRowsClickable()} and {@link #defineColumns(com.googlecode.gwtptk.client.DataTable.DataColumn...)} to complete
	 * the build of the data table.
	 */
	public DataTable() {
		setStyleName("data-table");
		setCellSpacing(0);
	}

	/**
	 * Makes rows of the table clickable - click then calls {@link #onRowClick(int, int)} method.
	 */
	protected void makeRowsClickable() {
		addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				HTMLTable.Cell cell = getCellForEvent(event);
				if (cell != null) {
					if (cell.getRowIndex() > 0) {
						int dataRow = cell.getRowIndex() - 1;
						if (!ignoreClicksOnColumns.contains(cell.getCellIndex())) {
							onRowClick(dataRow, cell.getCellIndex());
						}
					}
				}
			}
		});
	}

	/**
	 * Defines columns of the table.
	 *
	 * @param columns list of columns
	 */
	protected void defineColumns(DataColumn... columns) {
		// columnIndex solves discrepancy between setText (works seamlessly with span) and format setting
		// (where you have to calculate with spans)... just perfect
		int columnIndex = 0;
		int formatColumnIndex = 0;
		for (DataColumn column : columns) {
			setText(0, columnIndex, column.getName());
			if (column.getSpan() > 1) {
				getFlexCellFormatter().setColSpan(0, columnIndex, column.getSpan());
			}
			if (column.getWidth() != null) {
				getColumnFormatter().setWidth(formatColumnIndex, column.getWidth());
			}
			if (column.getStyle() != null) {
				getColumnFormatter().addStyleName(formatColumnIndex, column.getStyle());
			}
			if (column.isIgnoreRowClicks()) {
				ignoreClicksOnColumns.add(columnIndex);
			}
			columnIndex++;
			formatColumnIndex += column.getSpan();
		}
		getRowFormatter().addStyleName(0, "table-header-row");
	}

	/**
	 * Called after a row is clicked on. Should be override if you make data table with clickable rows.
	 *
	 * @param row line index (starting with 0)
	 * @param column column index (starting with 0)
	 */
	public void onRowClick(int row, int column) {
		// by default does nothing
	}

	@Override
	public void clear() {
		while (getRowCount() > 1) {
			removeRow(1);
		}
		row = 0;
	}

	public void addRow(Object... values) {
		addRowWithStyle(null, values);
	}

	public void addRowWithStyle(String styleName, Object... values) {
		if (styleName == null) {
			styleName = (row % 2 == 0) ? "table-odd-row" : "table-even-row";
		}
		getRowFormatter().addStyleName(++row, styleName);
		int columnIndex = 0;
		for (Object value : values) {
			if (value instanceof Widget) {
				setWidget(row, columnIndex, (Widget) value);
			} else {
				setText(row, columnIndex, value != null ? value.toString() : "");
			}
			columnIndex++;
		}
	}

	public static class DataColumn {
		private String name;
		private String width;
		private String style;
		private int span = 1;
		private boolean ignoreRowClicks;

		public DataColumn() {
		}

		public DataColumn(String name) {
			this.name = name;
		}

		public DataColumn setWidth(String width) {
			// problem with IE/Chrome, 0 is bad bad value ;-)
			if (width.equals("0") || width.equals("0px")) {
				width = "1px";
			}
			this.width = width;
			return this;
		}

		public DataColumn setMinWidth() {
			width = "1px";
			return this;
		}

		public DataColumn setSpan(int span) {
			this.span = span;
			return this;
		}

		public DataColumn setStyle(String style) {
			this.style = style;
			return this;
		}

		public DataColumn ignoreRowClicks() {
			ignoreRowClicks = true;
			return this;
		}

		public String getName() {
			return name;
		}

		public String getWidth() {
			return width;
		}

		public int getSpan() {
			return span;
		}

		public String getStyle() {
			return style;
		}

		public boolean isIgnoreRowClicks() {
			return ignoreRowClicks;
		}
	}
}
